package br.com.officium.jaas;

import br.com.officium.entidade.cadastro.Advogado;
import br.com.officium.entidade.cadastro.ClienteFisico;
import br.com.officium.entidade.cadastro.ClienteJuridico;
import br.com.officium.entidade.cadastro.Estagiario;
import br.com.officium.sessionbean.AdvogadoBsn;
import br.com.officium.sessionbean.ClienteFisicoBsn;
import br.com.officium.sessionbean.ClienteJuridicoBsn;
import br.com.officium.sessionbean.EstagiarioBsn;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;

/**
 * @author Ivo
 */
@Stateless
@LocalBean
public class AccessGroupBsn {

    public static final String ADMIN_GROUP = "admin";
    public static final String SUPERVISOR_GROUP = "supervisores";
    public static final String ADVOGADO_GROUP = "advogados";
    public static final String ESTAGIARIO_GROUP = "estaiarios";
    public static final String FISICO_GROUP = "fisicos";
    public static final String JURIDICO_GROUP = "juridicos";
    public static final String DEFAULT_GROUP = "members";
    
    @PersistenceContext
    private EntityManager em;
    
    @EJB
    private AdvogadoBsn advogadoBsn;
    
    
    @EJB
    private EstagiarioBsn estagiarioBsn;
    
    
    @EJB
    private ClienteFisicoBsn fisicoBsn;
    
    
    @EJB
    private ClienteJuridicoBsn juridicoBsn;
    
    @EJB
    private UserGroupBsn userGroupBsn;

    /**
     * Find an Access Group by ID.
     *
     * @param groupId
     * @return
     */
    public AccessGroup findAccessGroup(String groupId) {
        return em.find(AccessGroup.class, groupId);
    }

    /**
     * Find the user default group.
     *
     * @return
     */
    public AccessGroup findUserDefaultGroup() {
        AccessGroup defaultUserGroup = null;
        try {
            defaultUserGroup = (AccessGroup) em.createQuery("select ag from AccessGroup ag where ag.userDefault = :default").setParameter("default", Boolean.TRUE).getSingleResult();
        } catch (NoResultException nre) {
            defaultUserGroup = new AccessGroup(DEFAULT_GROUP, "Default Members Group");
            defaultUserGroup.setUserDefault(Boolean.TRUE);
            em.persist(defaultUserGroup);
        }
        return defaultUserGroup;
    }

    /**
     * Returns the existing administrative group. If it doesn't find anyone then
     * a new one is created and returned.
     *
     * @return admin group
     */
    public AccessGroup findAdministrativeGroup() {
        AccessGroup group = null;
        try {
            group = (AccessGroup) em.createQuery("select ag from AccessGroup ag where ag.name = :name").setParameter("name", ADMIN_GROUP).getSingleResult();
        } catch (Exception nre) {
            group = new AccessGroup(ADMIN_GROUP, "JUG Leaders Group");
            em.persist(group);
        }
        return group;
    }

    /**
     * Find all access group ordered by name.
     *
     * @return
     */
    public List<AccessGroup> findAccessGroups() {
        return em.createQuery("select ag from AccessGroup ag order by ag.name").getResultList();
    }

    /**
     * Find the access group by the name.
     *
     * @param name
     * @return
     */
    public AccessGroup findAccessGroupByName(String name) {
        try {
            return (AccessGroup) em.createQuery("select ag from AccessGroup ag where ag.name = :name").setParameter("name", name).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }

    /**
     * Save the Access group.
     *
     * @param accessGroup
     * @param members
     */
    public void saveAdvogado(AccessGroup accessGroup, List<Advogado> members) {
        if (accessGroup.getUserDefault()) {
            AccessGroup defaultGroup = findUserDefaultGroup();
            defaultGroup.setUserDefault(false);
        }

        if (accessGroup.getId() == null || accessGroup.getId().isEmpty()) {
            try {
                AccessGroup group = findAccessGroupByName(accessGroup.getName());
                if (group != null) {
                    throw new PersistenceException("A group named '" + accessGroup.getName() + "' already exists.");
                }
            } catch (NoResultException nre) {
                em.persist(accessGroup);
            }
        } else {
            em.merge(accessGroup);
        }

        if (members != null) {
            Advogado usr;
            List<UserGroup> usersGroup = new ArrayList<UserGroup>();
            for (Advogado member : members) {
                usr = advogadoBsn.find(member.getId());

                usersGroup.add(new UserGroup(accessGroup, usr));
            }
            userGroupBsn.update(accessGroup, usersGroup);
        }
    }

    /**
     * Save the Access group.
     *
     * @param accessGroup
     * @param members
     */
    public void saveEstagiario(AccessGroup accessGroup, List<Estagiario> members) {
        if (accessGroup.getUserDefault()) {
            AccessGroup defaultGroup = findUserDefaultGroup();
            defaultGroup.setUserDefault(false);
        }

        if (accessGroup.getId() == null || accessGroup.getId().isEmpty()) {
            try {
                AccessGroup group = findAccessGroupByName(accessGroup.getName());
                if (group != null) {
                    throw new PersistenceException("A group named '" + accessGroup.getName() + "' already exists.");
                }
            } catch (NoResultException nre) {
                em.persist(accessGroup);
            }
        } else {
            em.merge(accessGroup);
        }

        if (members != null) {
            Estagiario usr;
            List<UserGroup> usersGroup = new ArrayList<UserGroup>();
            for (Estagiario member : members) {
                usr = estagiarioBsn.find(member.getId());

                usersGroup.add(new UserGroup(accessGroup, usr));
            }
            userGroupBsn.update(accessGroup, usersGroup);
        }
    }

    /**
     * Save the Access group.
     *
     * @param accessGroup
     * @param members
     */
    public void saveFisico(AccessGroup accessGroup, List<ClienteFisico> members) {
        if (accessGroup.getUserDefault()) {
            AccessGroup defaultGroup = findUserDefaultGroup();
            defaultGroup.setUserDefault(false);
        }

        if (accessGroup.getId() == null || accessGroup.getId().isEmpty()) {
            try {
                AccessGroup group = findAccessGroupByName(accessGroup.getName());
                if (group != null) {
                    throw new PersistenceException("A group named '" + accessGroup.getName() + "' already exists.");
                }
            } catch (NoResultException nre) {
                em.persist(accessGroup);
            }
        } else {
            em.merge(accessGroup);
        }

        if (members != null) {
            ClienteFisico usr;
            List<UserGroup> usersGroup = new ArrayList<UserGroup>();
            for (ClienteFisico member : members) {
                usr = fisicoBsn.find(member.getId());

                usersGroup.add(new UserGroup(accessGroup, usr));
            }
            userGroupBsn.update(accessGroup, usersGroup);
        }
    }

    /**
     * Save the Access group.
     *
     * @param accessGroup
     * @param members
     */
    public void saveJuridico(AccessGroup accessGroup, List<ClienteJuridico> members) {
        if (accessGroup.getUserDefault()) {
            AccessGroup defaultGroup = findUserDefaultGroup();
            defaultGroup.setUserDefault(false);
        }

        if (accessGroup.getId() == null || accessGroup.getId().isEmpty()) {
            try {
                AccessGroup group = findAccessGroupByName(accessGroup.getName());
                if (group != null) {
                    throw new PersistenceException("A group named '" + accessGroup.getName() + "' already exists.");
                }
            } catch (NoResultException nre) {
                em.persist(accessGroup);
            }
        } else {
            em.merge(accessGroup);
        }

        if (members != null) {
            ClienteJuridico usr;
            List<UserGroup> usersGroup = new ArrayList<UserGroup>();
            for (ClienteJuridico member : members) {
                usr = juridicoBsn.find(member.getId());

                usersGroup.add(new UserGroup(accessGroup, usr));
            }
            userGroupBsn.update(accessGroup, usersGroup);
        }
    }

    /**
     * Remove the access group.
     *
     * @param groupId
     */
    public void remove(String groupId) {
        AccessGroup accessGroup = em.find(AccessGroup.class, groupId);
        em.remove(accessGroup);
    }
}